/*
 * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang.invoke;

import sun.invoke.util.Wrapper;
import java.lang.ref.WeakReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import sun.invoke.util.BytecodeDescriptor;
import static java.lang.invoke.MethodHandleStatics.*;
import sun.invoke.util.VerifyType;

/**
 * 方法类型表示方法句柄接受和返回的参数和返回类型，
 * 或者方法句柄调用者传递和期望的参数和返回类型。
 * 方法类型必须在方法句柄及其所有调用者之间正确匹配，
 * JVM的操作在特定时刻强制执行此匹配，特别是
 * 在调用{@link MethodHandle#invokeExact MethodHandle.invokeExact}
 * 和{@link MethodHandle#invoke MethodHandle.invoke}期间，
 * 以及在执行{@code invokedynamic}指令期间。
 * <p>
 * 结构是一个返回类型伴随任意数量的参数类型。
 * 类型（原始类型、{@code void}和引用类型）由{@link Class}对象表示。
 * （为了便于说明，我们将{@code void}视为一种类型。
 * 实际上，它表示没有返回类型。）
 * <p>
 * {@code MethodType}的所有实例都是不可变的。
 * 如果两个实例比较相等，则它们完全可以互换。
 * 相等性取决于返回类型和参数类型的成对对应关系，不依赖其他任何因素。
 * <p>
 * 此类型只能通过工厂方法创建。
 * 所有工厂方法都可能缓存值，尽管不保证缓存。
 * 一些工厂方法是静态的，而其他是虚方法，
 * 它们修改前驱方法类型，例如，通过更改选定的参数。
 * <p>
 * 操作参数类型组的工厂方法
 * 系统地以两个版本呈现，以便Java数组和
 * Java列表都可以用于处理参数类型组。
 * 查询方法{@code parameterArray}和{@code parameterList}
 * 也提供数组和列表之间的选择。
 * <p>
 * {@code MethodType} objects are sometimes derived from bytecode instructions
 * such as {@code invokedynamic}, specifically from the type descriptor strings associated
 * with the instructions in a class file's constant pool.
 * <p>
 * Like classes and strings, method types can also be represented directly
 * in a class file's constant pool as constants.
 * A method type may be loaded by an {@code ldc} instruction which refers
 * to a suitable {@code CONSTANT_MethodType} constant pool entry.
 * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
 * (For full details on method type constants,
 * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
 * <p>
 * When the JVM materializes a {@code MethodType} from a descriptor string,
 * all classes named in the descriptor must be accessible, and will be loaded.
 * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
 * This loading may occur at any time before the {@code MethodType} object is first derived.
 * @author John Rose, JSR 292 EG
 */
public final
class MethodType implements java.io.Serializable {
    private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}

    // The rtype and ptypes fields define the structural identity of the method type:
    private final Class<?>   rtype;
    private final Class<?>[] ptypes;

    // The remaining fields are caches of various sorts:
    private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
    private @Stable Object wrapAlt;  // alternative wrapped/unwrapped version and
                                     // private communication for readObject and readResolve
    private @Stable Invokers invokers;   // cache of handy higher-order adapters
    private @Stable String methodDescriptor;  // cache for toMethodDescriptorString

    /**
     * Check the given parameters for validity and store them into the final fields.
     */
    private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
        checkRtype(rtype);
        checkPtypes(ptypes);
        this.rtype = rtype;
        // defensively copy the array passed in by the user
        this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
    }

    /**
     * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
     * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
     * The parameters are reversed for this constructor, so that is is not accidentally used.
     */
    private MethodType(Class<?>[] ptypes, Class<?> rtype) {
        this.rtype = rtype;
        this.ptypes = ptypes;
    }

    /*trusted*/ MethodTypeForm form() { return form; }
    /*trusted*/ Class<?> rtype() { return rtype; }
    /*trusted*/ Class<?>[] ptypes() { return ptypes; }

    void setForm(MethodTypeForm f) { form = f; }

    /** This number, mandated by the JVM spec as 255,
     *  is the maximum number of <em>slots</em>
     *  that any Java method can receive in its argument list.
     *  It limits both JVM signatures and method type objects.
     *  The longest possible invocation will look like
     *  {@code staticMethod(arg1, arg2, ..., arg255)} or
     *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
     */
    /*non-public*/ static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.

    /** This number is the maximum arity of a method handle, 254.
     *  It is derived from the absolute JVM-imposed arity by subtracting one,
     *  which is the slot occupied by the method handle itself at the
     *  beginning of the argument list used to invoke the method handle.
     *  The longest possible invocation will look like
     *  {@code mh.invoke(arg1, arg2, ..., arg254)}.
     */
    // Issue:  Should we allow MH.invokeWithArguments to go to the full 255?
    /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1;  // deduct one for mh receiver

    /** This number is the maximum arity of a method handle invoker, 253.
     *  It is derived from the absolute JVM-imposed arity by subtracting two,
     *  which are the slots occupied by invoke method handle, and the
     *  target method handle, which are both at the beginning of the argument
     *  list used to invoke the target method handle.
     *  The longest possible invocation will look like
     *  {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
     */
    /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker

    private static void checkRtype(Class<?> rtype) {
        Objects.requireNonNull(rtype);
    }
    private static void checkPtype(Class<?> ptype) {
        Objects.requireNonNull(ptype);
        if (ptype == void.class)
            throw newIllegalArgumentException("parameter type cannot be void");
    }
    /** Return number of extra slots (count of long/double args). */
    private static int checkPtypes(Class<?>[] ptypes) {
        int slots = 0;
        for (Class<?> ptype : ptypes) {
            checkPtype(ptype);
            if (ptype == double.class || ptype == long.class) {
                slots++;
            }
        }
        checkSlotCount(ptypes.length + slots);
        return slots;
    }
    static void checkSlotCount(int count) {
        assert((MAX_JVM_ARITY & (MAX_JVM_ARITY+1)) == 0);
        // MAX_JVM_ARITY must be power of 2 minus 1 for following code trick to work:
        if ((count & MAX_JVM_ARITY) != count)
            throw newIllegalArgumentException("bad parameter count "+count);
    }
    private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
        if (num instanceof Integer)  num = "bad index: "+num;
        return new IndexOutOfBoundsException(num.toString());
    }

    static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();

    static final Class<?>[] NO_PTYPES = {};

    /**
     * 查找或创建给定方法类型的实例。
     * @param rtype  返回类型
     * @param ptypes 参数类型
     * @return 具有给定组件的方法类型
     * @throws NullPointerException 如果{@code rtype}或{@code ptypes}或{@code ptypes}的任何元素为null
     * @throws IllegalArgumentException 如果{@code ptypes}的任何元素为{@code void.class}
     */
    public static
    MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
        return makeImpl(rtype, ptypes, false);
    }

    /**
     * 查找或创建具有给定组件的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param rtype  返回类型
     * @param ptypes 参数类型
     * @return 具有给定组件的方法类型
     * @throws NullPointerException 如果{@code rtype}或{@code ptypes}或{@code ptypes}的任何元素为null
     * @throws IllegalArgumentException 如果{@code ptypes}的任何元素为{@code void.class}
     */
    public static
    MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
        boolean notrust = false;  // random List impl. could return evil ptypes array
        return makeImpl(rtype, listToArray(ptypes), notrust);
    }

    private static Class<?>[] listToArray(List<Class<?>> ptypes) {
        // sanity check the size before the toArray call, since size might be huge
        checkSlotCount(ptypes.size());
        return ptypes.toArray(NO_PTYPES);
    }

    /**
     * 查找或创建具有给定组件的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 前导参数类型被添加到剩余数组的前面。
     * @param rtype  返回类型
     * @param ptype0 第一个参数类型
     * @param ptypes 剩余的参数类型
     * @return 具有给定组件的方法类型
     * @throws NullPointerException 如果{@code rtype}或{@code ptype0}或{@code ptypes}或{@code ptypes}的任何元素为null
     * @throws IllegalArgumentException 如果{@code ptype0}或{@code ptypes}或{@code ptypes}的任何元素为{@code void.class}
     */
    public static
    MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
        Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
        ptypes1[0] = ptype0;
        System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
        return makeImpl(rtype, ptypes1, true);
    }

    /**
     * 查找或创建具有给定组件的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 结果方法没有参数类型。
     * @param rtype  返回类型
     * @return 具有给定返回值的方法类型
     * @throws NullPointerException 如果{@code rtype}为null
     */
    public static
    MethodType methodType(Class<?> rtype) {
        return makeImpl(rtype, NO_PTYPES, true);
    }

    /**
     * 查找或创建具有给定组件的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 结果方法具有单个给定的参数类型。
     * @param rtype  返回类型
     * @param ptype0 参数类型
     * @return 具有给定返回值和参数类型的方法类型
     * @throws NullPointerException 如果{@code rtype}或{@code ptype0}为null
     * @throws IllegalArgumentException 如果{@code ptype0}为{@code void.class}
     */
    public static
    MethodType methodType(Class<?> rtype, Class<?> ptype0) {
        return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
    }

    /**
     * 查找或创建具有给定组件的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 结果方法具有与{@code ptypes}相同的参数类型，
     * 以及指定的返回类型。
     * @param rtype  返回类型
     * @param ptypes 提供参数类型的方法类型
     * @return 具有给定组件的方法类型
     * @throws NullPointerException 如果{@code rtype}或{@code ptypes}为null
     */
    public static
    MethodType methodType(Class<?> rtype, MethodType ptypes) {
        return makeImpl(rtype, ptypes.ptypes, true);
    }

    /**
     * 查找或创建内部化方法类型的唯一工厂方法。
     * @param rtype 期望的返回类型
     * @param ptypes 期望的参数类型
     * @param trusted ptypes是否可以在不克隆的情况下使用
     * @return 具有期望结构的唯一方法类型
     */
    /*trusted*/ static
    MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
        MethodType mt = internTable.get(new MethodType(ptypes, rtype));
        if (mt != null)
            return mt;
        if (ptypes.length == 0) {
            ptypes = NO_PTYPES; trusted = true;
        }
        mt = new MethodType(rtype, ptypes, trusted);
        // promote the object to the Real Thing, and reprobe
        mt.form = MethodTypeForm.findForm(mt);
        return internTable.add(mt);
    }
    private static final MethodType[] objectOnlyTypes = new MethodType[20];

    /**
     * 查找或创建组件为{@code Object}且可选尾随{@code Object[]}数组的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 所有参数和返回类型都将是{@code Object}，
     * 除了最终的数组参数（如果有的话），它将是{@code Object[]}。
     * @param objectArgCount 参数数量（不包括最终的数组参数，如果有的话）
     * @param finalArray 是否会有尾随数组参数，类型为{@code Object[]}
     * @return 一般适用的方法类型，用于给定固定参数计数和收集的进一步参数数组的所有调用
     * @throws IllegalArgumentException 如果{@code objectArgCount}为负数或大于255（如果{@code finalArray}为true，则为254）
     * @see #genericMethodType(int)
     */
    public static
    MethodType genericMethodType(int objectArgCount, boolean finalArray) {
        MethodType mt;
        checkSlotCount(objectArgCount);
        int ivarargs = (!finalArray ? 0 : 1);
        int ootIndex = objectArgCount*2 + ivarargs;
        if (ootIndex < objectOnlyTypes.length) {
            mt = objectOnlyTypes[ootIndex];
            if (mt != null)  return mt;
        }
        Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
        Arrays.fill(ptypes, Object.class);
        if (ivarargs != 0)  ptypes[objectArgCount] = Object[].class;
        mt = makeImpl(Object.class, ptypes, true);
        if (ootIndex < objectOnlyTypes.length) {
            objectOnlyTypes[ootIndex] = mt;     // cache it here also!
        }
        return mt;
    }

    /**
     * 查找或创建组件全部为{@code Object}的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 所有参数和返回类型都将是Object。
     * @param objectArgCount 参数数量
     * @return 一般适用的方法类型，用于给定参数计数的所有调用
     * @throws IllegalArgumentException 如果{@code objectArgCount}为负数或大于255
     * @see #genericMethodType(int, boolean)
     */
    public static
    MethodType genericMethodType(int objectArgCount) {
        return genericMethodType(objectArgCount, false);
    }

    /**
     * 查找或创建具有单个不同参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param num    要更改的参数类型的索引（从零开始）
     * @param nptype 用于替换旧参数类型的新参数类型
     * @return 相同的类型，除了选定的参数已更改
     * @throws IndexOutOfBoundsException 如果{@code num}不是{@code parameterArray()}的有效索引
     * @throws IllegalArgumentException 如果{@code nptype}为{@code void.class}
     * @throws NullPointerException 如果{@code nptype}为null
     */
    public MethodType changeParameterType(int num, Class<?> nptype) {
        if (parameterType(num) == nptype)  return this;
        checkPtype(nptype);
        Class<?>[] nptypes = ptypes.clone();
        nptypes[num] = nptype;
        return makeImpl(rtype, nptypes, true);
    }

    /**
     * 查找或创建具有附加参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param num    插入参数类型的位置（从零开始）
     * @param ptypesToInsert 要插入到参数列表中的零个或多个新参数类型
     * @return 相同的类型，除了插入了选定的参数
     * @throws IndexOutOfBoundsException 如果{@code num}为负数或大于{@code parameterCount()}
     * @throws IllegalArgumentException 如果{@code ptypesToInsert}的任何元素为{@code void.class}
     *                                  或者如果结果方法类型将有超过255个参数槽
     * @throws NullPointerException 如果{@code ptypesToInsert}或其任何元素为null
     */
    public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
        int len = ptypes.length;
        if (num < 0 || num > len)
            throw newIndexOutOfBoundsException(num);
        int ins = checkPtypes(ptypesToInsert);
        checkSlotCount(parameterSlotCount() + ptypesToInsert.length + ins);
        int ilen = ptypesToInsert.length;
        if (ilen == 0)  return this;
        Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
        System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
        System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
        return makeImpl(rtype, nptypes, true);
    }

    /**
     * 查找或创建具有附加参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param ptypesToInsert 要在参数列表末尾插入的零个或多个新参数类型
     * @return 相同的类型，除了附加了选定的参数
     * @throws IllegalArgumentException 如果{@code ptypesToInsert}的任何元素为{@code void.class}
     *                                  或者如果结果方法类型将有超过255个参数槽
     * @throws NullPointerException 如果{@code ptypesToInsert}或其任何元素为null
     */
    public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
        return insertParameterTypes(parameterCount(), ptypesToInsert);
    }

    /**
     * 查找或创建具有附加参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param num    插入参数类型的位置（从零开始）
     * @param ptypesToInsert 要插入到参数列表中的零个或多个新参数类型
     * @return 相同的类型，除了插入了选定的参数
     * @throws IndexOutOfBoundsException 如果{@code num}为负数或大于{@code parameterCount()}
     * @throws IllegalArgumentException 如果{@code ptypesToInsert}的任何元素为{@code void.class}
     *                                  或者如果结果方法类型将有超过255个参数槽
     * @throws NullPointerException 如果{@code ptypesToInsert}或其任何元素为null
     */
    public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
        return insertParameterTypes(num, listToArray(ptypesToInsert));
    }

    /**
     * 查找或创建具有附加参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param ptypesToInsert 要在参数列表末尾插入的零个或多个新参数类型
     * @return 相同的类型，除了附加了选定的参数
     * @throws IllegalArgumentException 如果{@code ptypesToInsert}的任何元素为{@code void.class}
     *                                  或者如果结果方法类型将有超过255个参数槽
     * @throws NullPointerException 如果{@code ptypesToInsert}或其任何元素为null
     */
    public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
        return insertParameterTypes(parameterCount(), ptypesToInsert);
    }

     /**
     * 查找或创建具有修改参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param start  第一个被替换参数类型的位置（从零开始）
     * @param end    最后一个被替换参数类型之后的位置（从零开始）
     * @param ptypesToInsert 要插入到参数列表中的零个或多个新参数类型
     * @return 相同的类型，除了选定的参数被替换
     * @throws IndexOutOfBoundsException 如果{@code start}为负数或大于{@code parameterCount()}
     *                                  或者如果{@code end}为负数或大于{@code parameterCount()}
     *                                  或者如果{@code start}大于{@code end}
     * @throws IllegalArgumentException 如果{@code ptypesToInsert}的任何元素为{@code void.class}
     *                                  或者如果结果方法类型将有超过255个参数槽
     * @throws NullPointerException 如果{@code ptypesToInsert}或其任何元素为null
     */
    /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
        if (start == end)
            return insertParameterTypes(start, ptypesToInsert);
        int len = ptypes.length;
        if (!(0 <= start && start <= end && end <= len))
            throw newIndexOutOfBoundsException("start="+start+" end="+end);
        int ilen = ptypesToInsert.length;
        if (ilen == 0)
            return dropParameterTypes(start, end);
        return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
    }

    /** 用arrayType的组件类型替换最后arrayLength个参数类型。
     * @param arrayType 任何数组类型
     * @param arrayLength 要更改的参数类型数量
     * @return 结果类型
     */
    /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
        assert(parameterCount() >= arrayLength);
        int spreadPos = ptypes.length - arrayLength;
        if (arrayLength == 0)  return this;  // nothing to change
        if (arrayType == Object[].class) {
            if (isGeneric())  return this;  // nothing to change
            if (spreadPos == 0) {
                // no leading arguments to preserve; go generic
                MethodType res = genericMethodType(arrayLength);
                if (rtype != Object.class) {
                    res = res.changeReturnType(rtype);
                }
                return res;
            }
        }
        Class<?> elemType = arrayType.getComponentType();
        assert(elemType != null);
        for (int i = spreadPos; i < ptypes.length; i++) {
            if (ptypes[i] != elemType) {
                Class<?>[] fixedPtypes = ptypes.clone();
                Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
                return methodType(rtype, fixedPtypes);
            }
        }
        return this;  // arguments check out; no change
    }

    /** 返回前导参数类型，该类型必须存在且为引用类型。
     *  @return 错误检查后的前导参数类型
     */
    /*non-public*/ Class<?> leadingReferenceParameter() {
        Class<?> ptype;
        if (ptypes.length == 0 ||
            (ptype = ptypes[0]).isPrimitive())
            throw newIllegalArgumentException("no leading reference parameter");
        return ptype;
    }

    /** 删除最后一个参数类型，并用arrayType组件类型的arrayLength个副本替换它。
     * @param arrayType 任何数组类型
     * @param arrayLength 要插入的参数类型数量
     * @return 结果类型
     */
    /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
        assert(parameterCount() >= 1);
        assert(lastParameterType().isAssignableFrom(arrayType));
        MethodType res;
        if (arrayType == Object[].class) {
            res = genericMethodType(arrayLength);
            if (rtype != Object.class) {
                res = res.changeReturnType(rtype);
            }
        } else {
            Class<?> elemType = arrayType.getComponentType();
            assert(elemType != null);
            res = methodType(rtype, Collections.nCopies(arrayLength, elemType));
        }
        if (ptypes.length == 1) {
            return res;
        } else {
            return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
        }
    }

    /**
     * 查找或创建省略某些参数类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param start  要移除的第一个参数类型的索引（从零开始）
     * @param end    不移除的第一个参数类型的索引（大于{@code start}）
     * @return 相同的类型，除了移除了选定的参数
     * @throws IndexOutOfBoundsException 如果{@code start}为负数或大于{@code parameterCount()}
     *                                  或者如果{@code end}为负数或大于{@code parameterCount()}
     *                                  或者如果{@code start}大于{@code end}
     */
    public MethodType dropParameterTypes(int start, int end) {
        int len = ptypes.length;
        if (!(0 <= start && start <= end && end <= len))
            throw newIndexOutOfBoundsException("start="+start+" end="+end);
        if (start == end)  return this;
        Class<?>[] nptypes;
        if (start == 0) {
            if (end == len) {
                // drop all parameters
                nptypes = NO_PTYPES;
            } else {
                // drop initial parameter(s)
                nptypes = Arrays.copyOfRange(ptypes, end, len);
            }
        } else {
            if (end == len) {
                // drop trailing parameter(s)
                nptypes = Arrays.copyOfRange(ptypes, 0, start);
            } else {
                int tail = len - end;
                nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
                System.arraycopy(ptypes, end, nptypes, start, tail);
            }
        }
        return makeImpl(rtype, nptypes, true);
    }

    /**
     * 查找或创建具有不同返回类型的方法类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * @param nrtype 用于替换旧返回类型的返回参数类型
     * @return 相同的类型，除了返回类型已更改
     * @throws NullPointerException 如果{@code nrtype}为null
     */
    public MethodType changeReturnType(Class<?> nrtype) {
        if (returnType() == nrtype)  return this;
        return makeImpl(nrtype, ptypes, true);
    }

    /**
     * 报告此类型是否包含原始参数或返回值。
     * 返回类型{@code void}被视为原始类型。
     * @return 如果任何类型是原始类型则返回true
     */
    public boolean hasPrimitives() {
        return form.hasPrimitives();
    }

    /**
     * 报告此类型是否包含包装器参数或返回值。
     * 包装器是装箱原始值的类型，例如{@link Integer}。
     * 引用类型{@code java.lang.Void}被视为包装器，
     * 如果它作为返回类型出现。
     * @return 如果任何类型是包装器则返回true
     */
    public boolean hasWrappers() {
        return unwrap() != this;
    }

    /**
     * 将所有引用类型擦除为{@code Object}。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 所有原始类型（包括{@code void}）将保持不变。
     * @return 所有引用类型被替换的原始类型版本
     */
    public MethodType erase() {
        return form.erasedType();
    }

    /**
     * 将所有引用类型擦除为{@code Object}，将所有子字类型擦除为{@code int}。
     * 这是私有方法使用的简化类型多态性，
     * 例如{@link MethodHandle#invokeBasic invokeBasic}。
     * @return 所有引用和子字类型被替换的原始类型版本
     */
    /*non-public*/ MethodType basicType() {
        return form.basicType();
    }

    /**
     * @return 将MethodHandle作为第一个参数添加到原始类型前面的版本
     */
    /*non-public*/ MethodType invokerType() {
        return insertParameterTypes(0, MethodHandle.class);
    }

    /**
     * 将所有类型（引用类型和原始类型）转换为{@code Object}。
     * {@link #genericMethodType(int) genericMethodType}的便利方法。
     * 表达式{@code type.wrap().erase()}产生与
     * {@code type.generic()}相同的值。
     * @return 所有类型被替换的原始类型版本
     */
    public MethodType generic() {
        return genericMethodType(parameterCount());
    }

    /*non-public*/ boolean isGeneric() {
        return this == erase() && !hasPrimitives();
    }

    /**
     * 将所有原始类型转换为其对应的包装器类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 所有引用类型（包括包装器类型）将保持不变。
     * {@code void}返回类型被更改为类型{@code java.lang.Void}。
     * 表达式{@code type.wrap().erase()}产生与
     * {@code type.generic()}相同的值。
     * @return 所有原始类型被替换的原始类型版本
     */
    public MethodType wrap() {
        return hasPrimitives() ? wrapWithPrims(this) : this;
    }

    /**
     * 将所有包装器类型转换为其对应的原始类型。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 所有原始类型（包括{@code void}）将保持不变。
     * 返回类型{@code java.lang.Void}被更改为{@code void}。
     * @return 所有包装器类型被替换的原始类型版本
     */
    public MethodType unwrap() {
        MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
        return unwrapWithNoPrims(noprims);
    }

    private static MethodType wrapWithPrims(MethodType pt) {
        assert(pt.hasPrimitives());
        MethodType wt = (MethodType)pt.wrapAlt;
        if (wt == null) {
            // fill in lazily
            wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
            assert(wt != null);
            pt.wrapAlt = wt;
        }
        return wt;
    }

    private static MethodType unwrapWithNoPrims(MethodType wt) {
        assert(!wt.hasPrimitives());
        MethodType uwt = (MethodType)wt.wrapAlt;
        if (uwt == null) {
            // fill in lazily
            uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
            if (uwt == null)
                uwt = wt;    // type has no wrappers or prims at all
            wt.wrapAlt = uwt;
        }
        return uwt;
    }

    /**
     * 返回此方法类型中指定索引处的参数类型。
     * @param num 所需参数类型的索引（从零开始）
     * @return 选定的参数类型
     * @throws IndexOutOfBoundsException 如果{@code num}不是{@code parameterArray()}的有效索引
     */
    public Class<?> parameterType(int num) {
        return ptypes[num];
    }
    /**
     * 返回此方法类型中参数类型的数量。
     * @return 参数类型的数量
     */
    public int parameterCount() {
        return ptypes.length;
    }
    /**
     * 返回此方法类型的返回类型。
     * @return 返回类型
     */
    public Class<?> returnType() {
        return rtype;
    }

    /**
     * 将参数类型呈现为列表（便利方法）。
     * 该列表将是不可变的。
     * @return 参数类型（作为不可变列表）
     */
    public List<Class<?>> parameterList() {
        return Collections.unmodifiableList(Arrays.asList(ptypes.clone()));
    }

    /*non-public*/ Class<?> lastParameterType() {
        int len = ptypes.length;
        return len == 0 ? void.class : ptypes[len-1];
    }

    /**
     * 将参数类型呈现为数组（便利方法）。
     * 对数组的更改不会导致类型的更改。
     * @return 参数类型（如有必要，作为新副本）
     */
    public Class<?>[] parameterArray() {
        return ptypes.clone();
    }

    /**
     * 将指定对象与此类型进行相等性比较。
     * 也就是说，当且仅当指定对象
     * 也是具有完全相同参数和返回类型的方法类型时，它返回<tt>true</tt>。
     * @param x 要比较的对象
     * @see Object#equals(Object)
     */
    @Override
    public boolean equals(Object x) {
        return this == x || x instanceof MethodType && equals((MethodType)x);
    }

    private boolean equals(MethodType that) {
        return this.rtype == that.rtype
            && Arrays.equals(this.ptypes, that.ptypes);
    }

    /**
     * 返回此方法类型的哈希码值。
     * 它被定义为与列表的哈希码相同，
     * 该列表的元素是返回类型，后跟
     * 参数类型。
     * @return 此方法类型的哈希码值
     * @see Object#hashCode()
     * @see #equals(Object)
     * @see List#hashCode()
     */
    @Override
    public int hashCode() {
      int hashCode = 31 + rtype.hashCode();
      for (Class<?> ptype : ptypes)
          hashCode = 31*hashCode + ptype.hashCode();
      return hashCode;
    }

    /**
     * 返回方法类型的字符串表示，
     * 形式为{@code "(PT0,PT1...)RT"}。
     * 方法类型的字符串表示是一个
     * 用括号括起来的、逗号分隔的类型名称列表，
     * 紧接着是返回类型。
     * <p>
     * 每个类型都由其
     * {@link java.lang.Class#getSimpleName 简单名称}表示。
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("(");
        for (int i = 0; i < ptypes.length; i++) {
            if (i > 0)  sb.append(",");
            sb.append(ptypes[i].getSimpleName());
        }
        sb.append(")");
        sb.append(rtype.getSimpleName());
        return sb.toString();
    }

    /** 如果旧返回类型总是可以在新返回类型下查看（无需转换），
     *  并且新参数可以在旧参数类型下查看（无需转换），则为true。
     */
    /*non-public*/
    boolean isViewableAs(MethodType newType, boolean keepInterfaces) {
        if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces))
            return false;
        return parametersAreViewableAs(newType, keepInterfaces);
    }
    /** 如果新参数可以在旧参数类型下查看（无需转换），则为true。 */
    /*non-public*/
    boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces) {
        if (form == newType.form && form.erasedType == this)
            return true;  // my reference parameters are all Object
        if (ptypes == newType.ptypes)
            return true;
        int argc = parameterCount();
        if (argc != newType.parameterCount())
            return false;
        for (int i = 0; i < argc; i++) {
            if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), keepInterfaces))
                return false;
        }
        return true;
    }
    /*non-public*/
    boolean isConvertibleTo(MethodType newType) {
        MethodTypeForm oldForm = this.form();
        MethodTypeForm newForm = newType.form();
        if (oldForm == newForm)
            // same parameter count, same primitive/object mix
            return true;
        if (!canConvert(returnType(), newType.returnType()))
            return false;
        Class<?>[] srcTypes = newType.ptypes;
        Class<?>[] dstTypes = ptypes;
        if (srcTypes == dstTypes)
            return true;
        int argc;
        if ((argc = srcTypes.length) != dstTypes.length)
            return false;
        if (argc <= 1) {
            if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0]))
                return false;
            return true;
        }
        if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) ||
            (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) {
            // Somewhat complicated test to avoid a loop of 2 or more trips.
            // If either type has only Object parameters, we know we can convert.
            assert(canConvertParameters(srcTypes, dstTypes));
            return true;
        }
        return canConvertParameters(srcTypes, dstTypes);
    }

    /** 如果MHs.explicitCastArguments产生与MH.asType相同的结果，则返回true。
     *  如果任一类型转换不可能，结果应为false。
     */
    /*non-public*/
    boolean explicitCastEquivalentToAsType(MethodType newType) {
        if (this == newType)  return true;
        if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) {
            return false;
        }
        Class<?>[] srcTypes = newType.ptypes;
        Class<?>[] dstTypes = ptypes;
        if (dstTypes == srcTypes) {
            return true;
        }
        assert(dstTypes.length == srcTypes.length);
        for (int i = 0; i < dstTypes.length; i++) {
            if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
                return false;
            }
        }
        return true;
    }

    /** 如果src可以通过asType和MHs.eCE转换为dst，
     *  并且具有相同的效果，则报告true。
     *  MHs.eCA对MH.asType有以下"升级"：
     *  1. 接口是未检查的（即，被视为别名为Object）
     *     因此，{@code Object->CharSequence}在两种情况下都是可能的，但语义不同
     *  2. 支持原始类型到原始类型转换的完整矩阵
     *     像{@code long->byte}的窄化和像{@code boolean->int}的基本类型化
     *     不被asType支持，但asType支持的任何内容都与
     *     MHs.eCE等效。
     *  3a. 拆箱转换可以跟随原始转换的完整矩阵
     *  3b. 允许null的拆箱（创建零原始值）
     * 除了接口，引用到引用的转换是相同的。
     * 将原始类型装箱为引用对两个操作符都是相同的。
     */
    private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
        if (src == dst || dst == Object.class || dst == void.class)  return true;
        if (src.isPrimitive()) {
            // Could be a prim/prim conversion, where casting is a strict superset.
            // Or a boxing conversion, which is always to an exact wrapper class.
            return canConvert(src, dst);
        } else if (dst.isPrimitive()) {
            // Unboxing behavior is different between MHs.eCA & MH.asType (see 3b).
            return false;
        } else {
            // R->R always works, but we have to avoid a check-cast to an interface.
            return !dst.isInterface() || dst.isAssignableFrom(src);
        }
    }

    private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) {
        for (int i = 0; i < srcTypes.length; i++) {
            if (!canConvert(srcTypes[i], dstTypes[i])) {
                return false;
            }
        }
        return true;
    }

    /*non-public*/
    static boolean canConvert(Class<?> src, Class<?> dst) {
        // short-circuit a few cases:
        if (src == dst || src == Object.class || dst == Object.class)  return true;
        // the remainder of this logic is documented in MethodHandle.asType
        if (src.isPrimitive()) {
            // can force void to an explicit null, a la reflect.Method.invoke
            // can also force void to a primitive zero, by analogy
            if (src == void.class)  return true;  //or !dst.isPrimitive()?
            Wrapper sw = Wrapper.forPrimitiveType(src);
            if (dst.isPrimitive()) {
                // P->P must widen
                return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
            } else {
                // P->R must box and widen
                return dst.isAssignableFrom(sw.wrapperType());
            }
        } else if (dst.isPrimitive()) {
            // any value can be dropped
            if (dst == void.class)  return true;
            Wrapper dw = Wrapper.forPrimitiveType(dst);
            // R->P must be able to unbox (from a dynamically chosen type) and widen
            // For example:
            //   Byte/Number/Comparable/Object -> dw:Byte -> byte.
            //   Character/Comparable/Object -> dw:Character -> char
            //   Boolean/Comparable/Object -> dw:Boolean -> boolean
            // This means that dw must be cast-compatible with src.
            if (src.isAssignableFrom(dw.wrapperType())) {
                return true;
            }
            // The above does not work if the source reference is strongly typed
            // to a wrapper whose primitive must be widened.  For example:
            //   Byte -> unbox:byte -> short/int/long/float/double
            //   Character -> unbox:char -> int/long/float/double
            if (Wrapper.isWrapperType(src) &&
                dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
                // can unbox from src and then widen to dst
                return true;
            }
            // We have already covered cases which arise due to runtime unboxing
            // of a reference type which covers several wrapper types:
            //   Object -> cast:Integer -> unbox:int -> long/float/double
            //   Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
            // An marginal case is Number -> dw:Character -> char, which would be OK if there were a
            // subclass of Number which wraps a value that can convert to char.
            // Since there is none, we don't need an extra check here to cover char or boolean.
            return false;
        } else {
            // R->R always works, since null is always valid dynamically
            return true;
        }
    }

    /// Queries which have to do with the bytecode architecture

    /** 报告调用此类型方法所需的JVM栈槽数量。
     * 注意（由于历史原因）JVM需要
     * 第二个栈槽来传递long和double参数。
     * 因此此方法返回{@link #parameterCount() parameterCount}加上
     * long和double参数的数量（如果有的话）。
     * <p>
     * 包含此方法是为了那些必须
     * 生成处理方法句柄和invokedynamic的字节码的应用程序的利益。
     * @return 此类型参数的JVM栈槽数量
     */
    /*non-public*/ int parameterSlotCount() {
        return form.parameterSlotCount();
    }

    /*non-public*/ Invokers invokers() {
        Invokers inv = invokers;
        if (inv != null)  return inv;
        invokers = inv = new Invokers(this);
        return inv;
    }

    /** Reports the number of JVM stack slots which carry all parameters including and after
     * the given position, which must be in the range of 0 to
     * {@code parameterCount} inclusive.  Successive parameters are
     * 更浅层堆叠，参数在字节码中根据其尾边进行索引。
     * 因此，要获得参数{@code N}在传出调用栈中的深度，
     * 获取其在位置{@code N+1}处尾边的{@code parameterSlotDepth}。
     * <p>
     * 类型为{@code long}和{@code double}的参数占用
     * 两个栈槽（由于历史原因），所有其他参数占用一个。
     * 因此，返回的数字是<em>包括</em>和<em>在</em>给定参数<em>之后</em>的参数数量，
     * <em>加上</em>在给定参数的参数处或之后的long或double参数数量。
     * <p>
     * 包含此方法是为了那些必须
     * 生成处理方法句柄和invokedynamic的字节码的应用程序的利益。
     * @param num 参数类型中的索引（从零开始，包含）
     * @return 传输给定参数的（最浅）JVM栈槽的索引
     * @throws IllegalArgumentException 如果{@code num}为负数或大于{@code parameterCount()}
     */
    /*non-public*/ int parameterSlotDepth(int num) {
        if (num < 0 || num > ptypes.length)
            parameterType(num);  // force a range check
        return form.parameterToArgSlot(num-1);
    }

    /** 报告从此类型方法接收返回值所需的JVM栈槽数量。
     * 如果{@link #returnType() 返回类型}是void，它将是零，
     * 否则如果返回类型是long或double，它将是二，否则是一。
     * <p>
     * 包含此方法是为了那些必须
     * 生成处理方法句柄和invokedynamic的字节码的应用程序的利益。
     * @return 此类型返回值的JVM栈槽数量（0、1或2）
     * 将在PFD中移除。
     */
    /*non-public*/ int returnSlotCount() {
        return form.returnSlotCount();
    }

    /**
     * 根据其字节码描述符的拼写查找或创建方法类型的实例。
     * {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}的便利方法。
     * 嵌入在描述符字符串中的任何类或接口名称
     * 将通过在给定加载器上调用{@link ClassLoader#loadClass(java.lang.String)}
     * 来解析（或者如果它为null，则在系统类加载器上）。
     * <p>
     * 注意，可能会遇到无法通过此方法构造的方法类型，
     * 因为它们的组件类型并非都可以从公共类加载器访问。
     * <p>
     * 包含此方法是为了那些必须
     * 生成处理方法句柄和{@code invokedynamic}的字节码的应用程序的利益。
     * @param descriptor 字节码级别的类型描述符字符串"(T...)T"
     * @param loader 用于查找类型的类加载器
     * @return 匹配字节码级别类型描述符的方法类型
     * @throws NullPointerException 如果字符串为null
     * @throws IllegalArgumentException 如果字符串格式不正确
     * @throws TypeNotPresentException 如果找不到命名类型
     */
    public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
        throws IllegalArgumentException, TypeNotPresentException
    {
        if (!descriptor.startsWith("(") ||  // also generates NPE if needed
            descriptor.indexOf(')') < 0 ||
            descriptor.indexOf('.') >= 0)
            throw newIllegalArgumentException("not a method descriptor: "+descriptor);
        List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
        Class<?> rtype = types.remove(types.size() - 1);
        checkSlotCount(types.size());
        Class<?>[] ptypes = listToArray(types);
        return makeImpl(rtype, ptypes, true);
    }

    /**
     * 生成方法类型的字节码描述符表示。
     * <p>
     * 注意这不是{@link #fromMethodDescriptorString fromMethodDescriptorString}的严格逆操作。
     * 两个共享公共名称但具有不同类加载器的不同类
     * 在描述符字符串中查看时将显示相同。
     * <p>
     * 包含此方法是为了那些必须
     * 生成处理方法句柄和{@code invokedynamic}的字节码的应用程序的利益。
     * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString}，
     * 因为后者需要合适的类加载器参数。
     * @return 字节码类型描述符表示
     */
    public String toMethodDescriptorString() {
        String desc = methodDescriptor;
        if (desc == null) {
            desc = BytecodeDescriptor.unparse(this);
            methodDescriptor = desc;
        }
        return desc;
    }

    /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
        return BytecodeDescriptor.unparse(cls);
    }

    /// Serialization.

    /**
     * {@code MethodType}没有可序列化的字段。
     */
    private static final java.io.ObjectStreamField[] serialPersistentFields = { };

    /**
     * 将{@code MethodType}实例保存到流中。
     *
     * @serialData
     * 为了可移植性，序列化格式不引用命名字段。
     * 相反，返回类型和参数类型数组直接从{@code writeObject}方法写入，
     * 使用两次对{@code s.writeObject}的调用，如下所示：
     * <blockquote><pre>{@code
s.writeObject(this.returnType());
s.writeObject(this.parameterArray());
     * }</pre></blockquote>
     * <p>
     * 反序列化的字段值被检查，就像它们被
     * 提供给工厂方法{@link #methodType(Class,Class[]) methodType}一样。
     * 例如，null值或{@code void}参数类型
     * 将在反序列化期间导致异常。
     * @param s 要写入对象的流
     * @throws java.io.IOException 如果写入对象时出现问题
     */
    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
        s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
        s.writeObject(returnType());
        s.writeObject(parameterArray());
    }

    /**
     * 从流中重构{@code MethodType}实例（即，
     * 反序列化它）。
     * 此实例是具有虚假final字段的临时对象。
     * 它为{@link #readResolve readResolve}调用的工厂方法
     * 提供参数。
     * 在该调用之后它被丢弃。
     * @param s 要从中读取对象的流
     * @throws java.io.IOException 如果读取对象时出现问题
     * @throws ClassNotFoundException 如果无法解析组件类之一
     * @see #readResolve
     * @see #writeObject
     */
    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
        // Assign defaults in case this object escapes
        UNSAFE.putObject(this, rtypeOffset, void.class);
        UNSAFE.putObject(this, ptypesOffset, NO_PTYPES);

        s.defaultReadObject();  // requires serialPersistentFields to be an empty array

        Class<?>   returnType     = (Class<?>)   s.readObject();
        Class<?>[] parameterArray = (Class<?>[]) s.readObject();
        // Verify all operands, and make sure ptypes is unshared
        // Cache the new MethodType for readResolve
        wrapAlt = new MethodType[]{MethodType.methodType(returnType, parameterArray)};
    }

    // Support for resetting final fields while deserializing
    private static final long rtypeOffset, ptypesOffset;
    static {
        try {
            rtypeOffset = UNSAFE.objectFieldOffset
                (MethodType.class.getDeclaredField("rtype"));
            ptypesOffset = UNSAFE.objectFieldOffset
                (MethodType.class.getDeclaredField("ptypes"));
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    /**
     * 在序列化后解析和初始化{@code MethodType}对象。
     * @return 完全初始化的{@code MethodType}对象
     */
    private Object readResolve() {
        // Do not use a trusted path for deserialization:
        //    return makeImpl(rtype, ptypes, true);
        // Verify all operands, and make sure ptypes is unshared:
        // Return a new validated MethodType for the rtype and ptypes passed from readObject.
        MethodType mt = ((MethodType[])wrapAlt)[0];
        wrapAlt = null;
        return mt;
    }

    /**
     * 弱并发内部化集合的简单实现。
     *
     * @param <T> 内部化类型
     */
    private static class ConcurrentWeakInternSet<T> {

        private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
        private final ReferenceQueue<T> stale;

        public ConcurrentWeakInternSet() {
            this.map = new ConcurrentHashMap<>();
            this.stale = new ReferenceQueue<>();
        }

        /**
         * 获取现有的内部化元素。
         * 如果没有元素被内部化，此方法返回null。
         *
         * @param elem 要查找的元素
         * @return 内部化的元素
         */
        public T get(T elem) {
            if (elem == null) throw new NullPointerException();
            expungeStaleElements();

            WeakEntry<T> value = map.get(new WeakEntry<>(elem));
            if (value != null) {
                T res = value.get();
                if (res != null) {
                    return res;
                }
            }
            return null;
        }

        /**
         * 内部化元素。
         * 总是返回非null元素，匹配内部化集合中的元素。
         * 在与另一个add()的竞争下，如果另一个线程抢先内部化它，
         * 它可以返回<i>不同的</i>元素。
         *
         * @param elem 要添加的元素
         * @return 实际添加的元素
         */
        public T add(T elem) {
            if (elem == null) throw new NullPointerException();

            // Playing double race here, and so spinloop is required.
            // First race is with two concurrent updaters.
            // Second race is with GC purging weak ref under our feet.
            // Hopefully, we almost always end up with a single pass.
            T interned;
            WeakEntry<T> e = new WeakEntry<>(elem, stale);
            do {
                expungeStaleElements();
                WeakEntry<T> exist = map.putIfAbsent(e, e);
                interned = (exist == null) ? elem : exist.get();
            } while (interned == null);
            return interned;
        }

        private void expungeStaleElements() {
            Reference<? extends T> reference;
            while ((reference = stale.poll()) != null) {
                map.remove(reference);
            }
        }

        private static class WeakEntry<T> extends WeakReference<T> {

            public final int hashcode;

            public WeakEntry(T key, ReferenceQueue<T> queue) {
                super(key, queue);
                hashcode = key.hashCode();
            }

            public WeakEntry(T key) {
                super(key);
                hashcode = key.hashCode();
            }

            @Override
            public boolean equals(Object obj) {
                if (obj instanceof WeakEntry) {
                    Object that = ((WeakEntry) obj).get();
                    Object mine = get();
                    return (that == null || mine == null) ? (this == obj) : mine.equals(that);
                }
                return false;
            }

            @Override
            public int hashCode() {
                return hashcode;
            }

        }
    }

}
